package com.tanhua.manage.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.tanhua.common.enums.SexEnum;
import com.tanhua.manage.enums.AgeRangeEnum;
import com.tanhua.manage.enums.AreaEnum;
import com.tanhua.manage.mapper.AnalysisByDayMapper;
import com.tanhua.manage.mapper.UserInfoMapper;
import com.tanhua.manage.mapper.UserMapper;
import com.tanhua.manage.pojo.AnalysisByDay;
import com.tanhua.manage.pojo.Log;
import com.tanhua.manage.vo.AnalysisDistributionVo;
import com.tanhua.manage.vo.AnalysisUsersVo;
import com.tanhua.manage.vo.DataPointVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mxk
 * @date 2021/3/29 14:38
 */
@Service
public class AnalysisService extends ServiceImpl<AnalysisByDayMapper, AnalysisByDay> {

    @Autowired
    private AnalysisByDayMapper analysisByDayMapper;
    @Autowired
    private LogService logService;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserInfoMapper userInfoMapper;
    /**
     * 查询今日活跃用户数量
     * @param
     * @return
     */
    public Long queryActiveUserCountDay(DateTime today) {
        AnalysisByDay analysisByDay = analysisByDayMapper.selectOne(Wrappers.<AnalysisByDay>query().eq("record_date", today.toDateStr()));
        Long count=0L;
        if(analysisByDay==null){
            return count;
        }
        count=analysisByDay.getNumActive().longValue();
        return count;
    }
    /**
     * 查询昨日活跃用户数
     * @param today
     * @return
     */
    public Long queryActiveUserCountYesterday(DateTime today) {
        AnalysisByDay analysisByDay = analysisByDayMapper.selectOne(Wrappers.<AnalysisByDay>query().eq("record_date", DateUtil.offsetDay(today, -1).toDateStr()));
        Long count=0L;
        if(analysisByDay==null){
            return count;
        }
        count=analysisByDay.getNumActive().longValue();
        return count;
    }
    /**
     * 查询7天内活跃用户数
     * @param today
     * @return
     */
    public Long queryActiveUserCountWeek(DateTime today){
        int count = logService.count(Wrappers.<Log>query().select("DISTINCT(user_id)")
                .le("log_time", today.toDateStr())
                .ge("log_time", DateUtil.offsetDay(today, -7).toDateStr()));
        return Long.valueOf(count);
    }
    /**
     * 查询30天内活跃用户数
     * @param today
     * @return
     */
    public Long queryActiveUserCountMonth(DateTime today){
        int count = logService.count(Wrappers.<Log>query().select("DISTINCT(user_id)")
                .le("log_time", today.toDateStr())
                .ge("log_time", DateUtil.offsetDay(today, -30).toDateStr()));
        return Long.valueOf(count);
    }
    //====================================================================
    /**
     * 查询注册用户数量
     * @param
     * @param i
     * @return
     */
    public Long queryRegisterUserCount(DateTime today, int i) {
        return queryUserCount(today,i,"num_registered");
    }
    /**
     * 查询登录用户数量
     * @param today
     * @param i
     * @return
     */
    public Long queryLoginUserCount(DateTime today, int i) {
        return queryUserCount(today,i,"num_login");
    }
    private Long queryUserCount(DateTime today, int i, String colum) {
        AnalysisByDay analysisByDay = super.getOne(Wrappers.<AnalysisByDay>query().select("SUM(" + colum + ") AS num_active")
                .le("record_date", today.toDateStr())
                .ge("record_date", DateUtil.offsetDay(today, i).toDateStr()));
        Long count=0L;
        if(analysisByDay==null){
            return count;
        }
        count=analysisByDay.getNumActive().longValue();
        return count;
    }

    /**
     * 2.新增 活跃用户 次日留存率
     * @param sd
     * @param ed
     * @param type
     * @return
     */
    public AnalysisUsersVo queryAnalysisUsersVo(Long sd, Long ed, Integer type) {
        //开始时间
        DateTime startDate = DateUtil.date(sd);
        //结束时间
        DateTime endDate = DateUtil.date(ed);

        AnalysisUsersVo analysisUsersVo = new AnalysisUsersVo();
        //今年数据
        analysisUsersVo.setThisYear(queryDataPointVos(startDate,endDate,type));
        //去年数据  去年的日期表示使用DateUtil工具类
        analysisUsersVo.setLastYear(queryDataPointVos(DateUtil.offset(startDate, DateField.YEAR,-1),
                                                        DateUtil.offset(endDate,DateField.YEAR,-1),type));
        return analysisUsersVo;
    }

    private List<DataPointVo> queryDataPointVos(DateTime sd, DateTime ed, Integer type) {
        String startDate = sd.toDateStr();
        String endDate = ed.toDateStr();
        String column=null;//column:列
        switch (type){//101 新增  102 活跃用户  103 次日留存率
            case 101:
                column="num_registered";
                break;
            case 102:
                column="num_active";
                break;
            case 103:
                column="num_retention1d";
                break;
                default:
                    column="num_active";
                    break;
        }
        List<AnalysisByDay> analysisByDayList = super.list(Wrappers.<AnalysisByDay>query().select("record_date ," + column + " as num_active")
                .ge("record_date", startDate)
                .le("record_date", endDate));

        //将得到的AnalysisByDay集合提取其中的日期和类型对应的统计数整合为DataPointVo集合
       /* List<DataPointVo> dataPointVos = new ArrayList<>();
        for (AnalysisByDay analysisByDay : analysisByDayList) {
            DataPointVo dataPointVo = new DataPointVo();
            dataPointVo.setTitle(DateUtil.date(analysisByDay.getRecordDate()).toDateStr());
            dataPointVo.setAmount(analysisByDay.getNumActive().longValue());
            dataPointVos.add(dataPointVo);
        }
        return dataPointVos;*/
        //map():用于映射每个元素到对应的结果
        //Collectors(): 类实现了很多归约操作，例如将流转换成集合和聚合元素
        //这里也可以使用for循环处理
        return analysisByDayList.stream()
                .map(analysisByDay -> new DataPointVo(DateUtil.date(analysisByDay.getRecordDate()).toDateStr(), analysisByDay.getNumActive().longValue()))
                .collect(Collectors.toList());
    }

    /**
     * 3.注册用户分布，行业top、年龄、性别、地区
     * @param sd
     * @param ed
     * @return
     */
    private static final String[] LOCALS = {"上海", "河北", "山西", "内蒙古", "辽宁", "吉林", "黑龙江", "江苏"
            , "浙江", "安徽", "福建", "江西", "山东", "河南", "湖北", "湖南", "广东", "广西", "海南", "四川"
            , "贵州", "云南", "西藏", "陕西", "甘肃", "青海", "宁夏", "新疆", "北京", "天津", "重庆", "香港"
            , "澳门", "台湾", "南海诸岛"};
    public AnalysisDistributionVo queryUserDistribution(Long sd, Long ed) {
        String startDate = DateUtil.date(sd).toDateStr();
        String endDate = DateUtil.date(ed).toDateStr();
        AnalysisDistributionVo analysisDistributionVo = new AnalysisDistributionVo();

        //行业top10
        analysisDistributionVo.setIndustryDistribution(this.userInfoMapper.findIndustryDistribution(startDate, endDate));

        //年龄分布
        analysisDistributionVo.setAgeDistribution(new ArrayList<>());
        for (AgeRangeEnum ageRangeEnum : AgeRangeEnum.values()) {
            Long amount = userInfoMapper.countByAge(ageRangeEnum.getMin(), ageRangeEnum.getMax(), startDate, endDate);
            analysisDistributionVo.getAgeDistribution().add(new DataPointVo(ageRangeEnum.getDesc(), amount));
        }

        //性别分布  使用流
        analysisDistributionVo.setGenderDistribution(this.userInfoMapper.findGenderDistribution(startDate, endDate)
                .stream().map(dataPointVo -> {
                    dataPointVo.setTitle(SexEnum.getSexByValue(Integer.valueOf(dataPointVo.getTitle())));
                    return dataPointVo;
                }).collect(Collectors.toList()));


        //地区分布
        analysisDistributionVo.setLocalDistribution(new ArrayList<>());
        for (String local : LOCALS) {
            Long amount = userInfoMapper.countByProvince(local + "%", startDate, endDate);
            analysisDistributionVo.getLocalDistribution().add(new DataPointVo(local, amount));
        }

        // 地区汇总数据
        Map<String, Long> areaMap = new HashMap<>();
        analysisDistributionVo.getLocalDistribution().forEach(dataPoint -> {
            String area = AreaEnum.getAreaByProvince(dataPoint.getTitle());
            areaMap.put(area, MapUtil.getLong(areaMap, area, 0L) + dataPoint.getAmount());
        });

        analysisDistributionVo.setLocalTotal(
                areaMap.entrySet().stream()
                        .map(entry -> new DataPointVo(entry.getKey(), entry.getValue()))
                        .sorted(Comparator.comparing(DataPointVo::getAmount).reversed())
                        .collect(Collectors.toList()));

        return analysisDistributionVo;
    }
}
